#include "sd_spi.h"
#include "board_init.h"
#define SD_SPI SPI2
#define SD_DUMMY_BYTE   0xFF

uint8_t SD_TYPE = 0;


//static volatile DSTATUS Stat = STA_NOINIT;              /* 디스크 상태 Flag*/
static uint8_t CardType;                                /* SD 타입 0:MMC, 1:SDC, 2:Block addressing */
static uint8_t PowerFlag = 0;                           /* Power 상태 Flag */






#if  0

/* xfer data by spi port. */
static uint8_t spi_xfer(const uint8_t value)
{
    while(0 == (SPI_GetStatus(SD_SPI) & SPI_STATUS_TX_EMPTY) )
    {}
    SPI_PutData(SD_SPI, value);

    while(0 == (SPI_GetStatus(SD_SPI) & SPI_STATUS_RX_DONE) )
    {}
    return SPI_GetData(SD_SPI);
}

//enable ==true    cs set low
//enable ==false   cs set high
static void spi_cs(bool enable)
{
	  if (true == enable)
    {
        GPIO_ClearBits(BOARD_FLASH_CS_GPIO_PORT, BOARD_FLASH_CS_GPIO_PIN);
    }
    else
    {
        GPIO_SetBits(BOARD_FLASH_CS_GPIO_PORT, BOARD_FLASH_CS_GPIO_PIN);
    }
}

static  void sd_send_cmd(uint8_t cmd,uint32_t arg,uint8_t crc)
{
	    uint8_t data[6] = {0};
    
    /* command bit7 is always 1, bit6 is always 0, see SD manual. */
    data[0] &= ~(0x80);
    data[0] = cmd | 0x40;
    data[1] = (uint8_t)(arg >> 24);
    data[2] = (uint8_t)(arg >> 16);
    data[3] = (uint8_t)(arg >> 8);
    data[4] = (uint8_t)(arg);
    data[5] = crc;
    for (int i = 0; i < 6; i ++)
        spi_xfer(data[i]);
}
static uint8_t sd_read_response(uint8_t response)
{
    uint32_t repeat = 0xfff;
    while (repeat --) {
        if (spi_xfer(SD_DUMMY_BYTE) == response)
            break;
    }
    if (repeat)
        return SD_RESPONSE_NO_ERROR;
    else
        return SD_RESPONSE_FAILURE;
}

void sd_power_on(void)
{
    spi_cs(false);
    uint32_t i = 0;
    for (i = 0; i <= 9; i++) {
        spi_xfer(SD_DUMMY_BYTE);
    } 
}
SD_ERROR set_sd_to_idle_state(void)
{
    uint32_t repeat = 0xfff;
    
    spi_cs(true);
    sd_send_cmd(SD_CMD_GO_IDLE_STATE, 0, 0x95);
    if (sd_read_response(SD_IN_IDLE_STATE))      //check card is idle
        return SD_RESPONSE_FAILURE;
    spi_cs(false);
    
    spi_xfer(SD_DUMMY_BYTE);    //release card
    if (repeat == 0)
        return SD_RESPONSE_FAILURE;
    else
        return SD_RESPONSE_NO_ERROR;
}
SD_ERROR get_sd_card_type(void)
{
    uint32_t i = 0;
    uint32_t count = 0xFFF;

    uint8_t R7R3_Resp[4];
    uint8_t R1_Resp;
  
	spi_cs(false);
	spi_xfer(SD_DUMMY_BYTE);
	
	spi_cs(true);
  sd_send_cmd(SD_CMD_SEND_IF_COND, 0x1AA, 0x87); 	

    /*!< Check if response is got or a timeout is happen */
    while (( (R1_Resp = spi_xfer(SD_DUMMY_BYTE)) == 0xFF) && count) {
        count--;
    }
    if (count == 0) {
        /*!< After time out */
        return 1;
    }

	//R1_Resp = 0x05   not v2.0 card
	if(R1_Resp == (SD_IN_IDLE_STATE|SD_ILLEGAL_COMMAND)) {  
        /*----------Activates the card initialization process-----------*/
        count = 0xfff;
		do {
			spi_cs(false);
            spi_xfer(SD_DUMMY_BYTE);
			
            spi_cs(true);
			//cmd 1 finish v1 card init
			sd_send_cmd(SD_CMD_SEND_OP_COND, 0, 0xFF);
			//!< Wait for no error Response (R1 Format) equal to 0x00 
            if (sd_read_response(SD_RESPONSE_NO_ERROR))
                break;
		} while (count --);
        if (count == 0) {
            return 2;
        }
		SD_Type = SD_TYPE_V1;
		//MMC card not action
		
		//init sucess
    } else if (R1_Resp == 0x01) {   //resp=0x01  sd card is v2.0
        /*!< ??CMD8 ?R7?? */
        for (i = 0; i < 4; i++) {
            R7R3_Resp[i] = spi_xfer(SD_DUMMY_BYTE);
        }
        
        spi_cs(false);
        spi_xfer(SD_DUMMY_BYTE);
	
        spi_cs(true);
        if(R7R3_Resp[2]==0x01 && R7R3_Resp[3]==0xAA) {      //????????2.7-3.6V??
            count = 200;                                    //??????,????
            do {                                            //???????CMD55+ACMD41
                sd_send_cmd(SD_CMD_APP_CMD, 0, 0xFF); 	    //CMD55,???????ACMD??
                if (sd_read_response(SD_RESPONSE_NO_ERROR)) // SD_IN_IDLE_STATE
                    return 3;             //????
                sd_send_cmd(SD_ACMD_SD_SEND_OP_COND, 0x40000000, 0xFF);  //ACMD41???HCS???
                if (sd_read_response(SD_RESPONSE_NO_ERROR))
                    break;
            }while(count--);
            if(count == 0)
                return 4; //??????
            
            //???????,??OCR??,CMD58
            //-----------??SDSC SDHC?????-----------		
            count = 200;
            do {
                spi_cs(false);
                spi_xfer(SD_DUMMY_BYTE);
                spi_cs(true);
                sd_send_cmd(SD_CMD_READ_OCR, 0, 0xFF);
                if (!sd_read_response(SD_RESPONSE_NO_ERROR))
                    break;
            } while (count--);
            if(count == 0)
                return 5; //??????
            
            //????,??R3??
            /*!< ??CMD58?R3?? */
            for (i = 0; i < 4; i++) {
                R7R3_Resp[i] = spi_xfer(SD_DUMMY_BYTE);
            }		
						
            //?????OCR??bit30(CCS)
            //CCS = 0:SDSC			 CCS = 1:SDHC
            if(R7R3_Resp[0]&0x40) {    //??CCS?? {
                SD_Type = SD_TYPE_V2HC; 
            } else {
                SD_Type = SD_TYPE_V2;
            }
            //-----------??SDSC SDHC????????-----------			 
        }
    }

    spi_cs(false);
    spi_xfer(SD_DUMMY_BYTE);
	
	//???????
	return SD_RESPONSE_NO_ERROR;
}






#define SD_START_DATA_SINGLE_BLOCK_READ    0xFE  /*!< Data token start byte, Start Single Block Read */
#define SD_START_DATA_MULTIPLE_BLOCK_READ  0xFE  /*!< Data token start byte, Start Multiple Block Read */
#define SD_START_DATA_SINGLE_BLOCK_WRITE   0xFE  /*!< Data token start byte, Start Single Block Write */
#define SD_START_DATA_MULTIPLE_BLOCK_WRITE 0xFD  /*!< Data token start byte, Start Multiple Block Write */
#define SD_STOP_DATA_MULTIPLE_BLOCK_WRITE  0xFD  /*!< Data toke stop byte, Stop Multiple Block Write */

SD_ERROR sd_write_block(uint8_t* pbuf, uint64_t addr, uint16_t size)
{
    uint32_t i = 0;
    SD_ERROR ret = SD_RESPONSE_FAILURE;
	
	//SDHC???????512,????????????sector
	if (SD_Type == SD_TYPE_V2HC) {
        size = 512;
        addr /= 512;
    }

    /*!< SD chip select low */
    spi_cs(true);

    /*!< Send CMD24 (SD_CMD_WRITE_SINGLE_BLOCK) to write multiple block */
    sd_send_cmd(SD_CMD_WRITE_SINGLE_BLOCK, addr, 0xFF);
  
    /*!< Check if the SD acknowledged the write block command: R1 response (0x00: no errors) */
    if (!sd_read_response(SD_RESPONSE_NO_ERROR)) {
        /*!< Send a dummy byte */
        spi_xfer(SD_DUMMY_BYTE);

        /*!< Send the data token to signify the start of the data */
        spi_xfer(SD_START_DATA_SINGLE_BLOCK_WRITE);

        /*!< Write the block data to SD : write count data by block */
        for (i = 0; i < size; i++) {
            /*!< Send the pointed byte */
            spi_xfer(*pbuf);
            /*!< Point to the next location where the byte read will be saved */
            pbuf++;
        }
        
        /*!< Put CRC bytes (not really needed by us, but required by SD) */
        spi_xfer(SD_DUMMY_BYTE);
        spi_xfer(SD_DUMMY_BYTE);

        /*!< Read data response */
				#if 0
        if (sd_get_data_response() == SD_DATA_OK) {
            ret = SD_RESPONSE_NO_ERROR;
        }
				#endif
    }
    /*!< SD chip select high */
    spi_cs(false);
    /*!< Send dummy byte: 8 Clock pulses of delay */
    spi_xfer(SD_DUMMY_BYTE);

    /*!< Returns the reponse */
    return ret;
}


SD_ERROR sd_read_block(uint8_t* pbuf, uint64_t addr, uint16_t size)
{
  uint32_t i = 0;
  SD_ERROR ret = SD_RESPONSE_FAILURE;
	
	//SDHC???????512,????????????sector
    if (SD_Type == SD_TYPE_V2HC) {
        size = 512;
        addr /= 512;
    }

      /*!< SD chip select low */
      spi_cs(true);
  
    /*!< Send CMD17 (SD_CMD_READ_SINGLE_BLOCK) to read one block */
    sd_send_cmd(SD_CMD_READ_SINGLE_BLOCK, addr, 0xFF);
  
    /*!< Check if the SD acknowledged the read block command: R1 response (0x00: no errors) */
    if (!sd_read_response(SD_RESPONSE_NO_ERROR)) {
        /*!< Now look for the data token to signify the start of the data */
        if (!sd_read_response(SD_START_DATA_SINGLE_BLOCK_READ)) {
            /*!< Read the SD block data : read NumByteToRead data */
            for (i = 0; i < size; i++) {
                /*!< Save the received data */
                *pbuf = spi_xfer(SD_DUMMY_BYTE);

                /*!< Point to the next location where the byte read will be saved */
                pbuf++;
            }
        /*!< Get CRC bytes (not really needed by us, but required by SD) */
        spi_xfer(SD_DUMMY_BYTE);
        spi_xfer(SD_DUMMY_BYTE);
        /*!< Set response value to success */
        ret = SD_RESPONSE_NO_ERROR;
        }
    }
    /*!< SD chip select high */
    spi_cs(false);

    /*!< Send dummy byte: 8 Clock pulses of delay */
    spi_xfer(SD_DUMMY_BYTE);

    /*!< Returns the reponse */
    return ret;
}


#endif 












/*
static void spi_wr(const uint8_t *write_buf, size_t write_size, uint8_t *read_buf, size_t read_size)
{
		spi_cs(true);
	  // put data. 
    for (uint32_t i = 0u; i < write_size; i++)
    {
        spi_xfer(write_buf[i]);
    }
		 // recv data. 
    for (uint32_t i = 0u; i < read_size; i++)
    {
        read_buf[i] = spi_xfer(0xff);
    }
		spi_cs(false);
}
*/